#include <signal.h>

#include <QDebug>
#include <QString>
#include <QApplication>
#include <QHostAddress>
#include <QTcpSocket>

#include "lhws.h"



LHWS::LHWS (short listen_port, short remote_port, int latency, int throughput,
            QObject* parent)
  : QObject (parent), _remote_port (remote_port),
    _server (this), _server_queue (latency, throughput),
    _client_queue (latency, throughput)
{
  _server.setMaxPendingConnections (1);

  if (!_server.listen (QHostAddress ("127.0.0.1"), listen_port))
    qDebug () << "Unable to listen on" << listen_port;

  connect (&_server, SIGNAL (newConnection ()), SLOT (new_connection ()));
  connect (&_server_queue, SIGNAL (data_ready (const QByteArray&)),
    SLOT (server_queue_data_read (const QByteArray&)));
  connect (&_client_queue, SIGNAL (data_ready (const QByteArray&)),
    SLOT (client_queue_data_read (const QByteArray&)));
}

void LHWS::new_connection()
{
  _server_queue.clear ();
  _client_queue.clear ();

  _server_side = _server.nextPendingConnection ();

  qDebug () << "Connection from" << _server_side->peerAddress ();

  connect (_server_side, SIGNAL (disconnected ()),
           SLOT (server_disconnected ()));
  connect (_server_side, SIGNAL (readyRead ()),
           SLOT (server_data_ready ()));

  _client_side = new QTcpSocket ();
  _client_side->connectToHost ("127.0.0.1", _remote_port);

  connect (_client_side, SIGNAL (disconnected ()),
           SLOT (client_disconnected ()));
  connect (_client_side, SIGNAL (readyRead ()),
           SLOT (client_data_ready ()));
}

void LHWS::server_disconnected ()
{
  qDebug () << "Disconnection from the server";

  _server_side->deleteLater ();
  _server_side = nullptr;

  if (_client_side)
    _client_side->close ();
}

void LHWS::server_data_ready ()
{
  QByteArray data = _server_side->read (_server_side->bytesAvailable ());
  _server_queue.queue_data (data);
}

void LHWS::server_queue_data_read (const QByteArray& data)
{
  if (!_client_side)
    return;

  _client_side->write (data);
}

void LHWS::client_disconnected ()
{
  qDebug () << "Disconnection from the client";

  _client_side->deleteLater ();
  _client_side = nullptr;

  if (_server_side)
    _server_side->close ();
}

void LHWS::client_data_ready ()
{
  QByteArray data = _client_side->read (_client_side->bytesAvailable ());
  _client_queue.queue_data (data);
}

void LHWS::client_queue_data_read (const QByteArray& data)
{
  if (!_server_side)
    return;

  _server_side->write (data);
}



void sig_handler (int sig)
{
  if (sig == SIGINT)
    QCoreApplication::quit ();
}

int main (int argc, char** argv)
{
  QApplication app (argc, argv);

  if (argc != 5) {
    qDebug () << argv[0]
      << "[listen port] [remote port] [latency(ms)] [throughput(kbps)]";
    return 1;
  }

  short listen_port = QString (argv[1]).toShort ();
  short remote_port = QString (argv[2]).toShort ();
  int latency = QString (argv[3]).toInt ();
  int throughput = QString (argv[4]).toInt ();

  signal (SIGINT, sig_handler);

  LHWS lhws (listen_port, remote_port, latency, throughput);

  app.exec ();

  qDebug () << "Exiting...";
}
